package com.dnjn.happiness.emo.handler;

import com.dnjn.happiness.common.config.DateTimeFormatHolder;
import com.dnjn.happiness.common.config.ThreadPoolConfig;
import com.dnjn.happiness.common.core.constant.Constants;
import com.dnjn.happiness.common.core.constant.SecurityConstants;
import com.dnjn.happiness.common.core.domain.R;
import com.dnjn.happiness.common.core.utils.DateUtils;
import com.dnjn.happiness.common.core.utils.JsonUtils;
import com.dnjn.happiness.common.core.utils.StringUtils;
import com.dnjn.happiness.emo.api.RemoteEmoUserService;
import com.dnjn.happiness.emo.api.domain.EmoAvgScoreWeekly;
import com.dnjn.happiness.emo.api.model.EmoUserBean;
import com.dnjn.happiness.emo.service.IEmoAvgScoreDailyService;
import com.dnjn.happiness.emo.service.IEmoAvgScoreWeeklyService;
import com.dnjn.happiness.emo.api.domain.EmoAvgScoreDaily;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
@Component("computeHappinessScore")
public class ComputeHappinessScore {


    @Autowired
    private RemoteEmoUserService emoUserService;

    @Autowired
    private IEmoAvgScoreDailyService dailyService;

    @Autowired
    private IEmoAvgScoreWeeklyService weeklyService;

    final String ZERO = "0";

    /**
     * quartz：每天晚上十点 定时记录每个员工每天的平均快乐值
     */
//    @Scheduled(cron = "0/10 * * * * ?")
    public void computeDailyAvgScore() {
        Long totalCount = 0L;
        R<Long> result = emoUserService.getCount(SecurityConstants.INNER);
        if (StringUtils.isNotNull(result) && StringUtils.isNotNull(result.getData())) {
            totalCount = result.getData();
        }
        final int runSize = 10;
        final int pageSize = 1000;
        final int pageCount = totalCount % pageSize == 0 ? totalCount.intValue() / pageSize : totalCount.intValue() / pageSize + 1;//87
        ThreadPoolExecutor executor = ThreadPoolConfig.createThread(runSize);
        // 计算sql语句中每个分页查询的起始和结束数据下标
        // 循环创建线程
        //此处调用具体的查询方法 0,100, 101 201 ,
        log.info("定时记录用户每天均值开始查询emo_user");
        for (int i = 0; i < pageCount; i++) {
            Integer page = i * pageSize;
            executor.execute(() -> {
                log.info("每次查询的下标:" + page + ",条数:" + pageSize);
                List<EmoUserBean> userList = new ArrayList<>();
                R<List<EmoUserBean>> resultList = emoUserService.selectByLimit(page, pageSize, SecurityConstants.INNER);
                if (StringUtils.isNotNull(resultList) && StringUtils.isNotNull(resultList.getData())) {
                    userList = resultList.getData();
                }
                insertDailyAvgScore(userList);
            });
        }
        executor.shutdown();
    }

    private void insertDailyAvgScore(List<EmoUserBean> userList) {
        log.info("开始定时记录每个员工每天的平均快乐值======================");
        LocalDate now = LocalDate.now();
        log.info("计算日均当前时间======================", now.format(DateTimeFormatHolder.FORMATTER_YYYY_MM_DD));
        for (EmoUserBean emoUser : userList) {
            Long userId = emoUser.getUserId();
            //查出昨天日平均
            EmoAvgScoreDaily yesterdayDaily = dailyService.lambdaQuery()
                    .eq(EmoAvgScoreDaily::getCurrDate, now.minusDays(1)).eq(EmoAvgScoreDaily::getUserId, userId).one();
            BigDecimal currHappinessScore = BigDecimal.valueOf(emoUser.getHappinessScore());
            log.info("昨天日平均======================", yesterdayDaily, "userId：", userId);

            //查询是否有今天的日均，如果有就更新，没有就新增
            EmoAvgScoreDaily daily = dailyService.lambdaQuery()
                    .eq(EmoAvgScoreDaily::getCurrDate, now).eq(EmoAvgScoreDaily::getUserId, userId).one();
            log.info("今天的日均======================", daily, "userId：", userId);

            if (StringUtils.isNull(daily)) {
                daily = new EmoAvgScoreDaily()
                        .setUserId(userId)
                        .setCurrDate(now)
                        .setScoreAvg(currHappinessScore);
            } else {
                daily.setScoreAvg(currHappinessScore);
            }

            if (StringUtils.isNotNull(emoUser)) {
                daily.setNickName(emoUser.getNickName())
                        .setEmpno(emoUser.getEmpno());
            }
            if (StringUtils.isNotNull(yesterdayDaily) && StringUtils.isNotNull(yesterdayDaily.getScoreAvg())) {
                daily.setScoreChanged(currHappinessScore.subtract(yesterdayDaily.getScoreAvg()));
            }
            log.info("日均对象======================", daily);
            dailyService.saveOrUpdate(daily);

        }
        log.info("结束定时记录每个员工每天的平均快乐值======================");
    }

    /**
     * quartz：7小时算一次 每个员工每周的平均快乐值，
     * 如果没有这周这条记录（202401周）就新增，
     * 如果有周记录，就更新
     */
    public void computeWeeklyAvgScore() {
        Long totalCount = 0L;
        R<Long> result = emoUserService.getCount(SecurityConstants.INNER);
        if (StringUtils.isNotNull(result) && StringUtils.isNotNull(result.getData())) {
            totalCount = result.getData();
        }
        final int runSize = 10;
        final int pageSize = 1000;
        final int pageCount = totalCount % pageSize == 0 ? totalCount.intValue() / pageSize : totalCount.intValue() / pageSize + 1;
        ThreadPoolExecutor executor = ThreadPoolConfig.createThread(runSize);
        // 计算sql语句中每个分页查询的起始和结束数据下标
        // 循环创建线程
        //此处调用具体的查询方法 0,100, 101 201 ,
        log.info("定时记录用户每周均值开始查询emo_user");
        for (int i = 0; i < pageCount; i++) {
            Integer page = i * pageSize;
            executor.execute(() -> {
                log.info("每次查询的下标:" + page + ",条数:" + pageSize);
                List<EmoUserBean> userList = new ArrayList<>();
                R<List<EmoUserBean>> resultList = emoUserService.selectByLimit(page, pageSize, SecurityConstants.INNER);
                if (StringUtils.isNotNull(resultList) && StringUtils.isNotNull(resultList.getData())) {
                    userList = resultList.getData();
                }
                insertWeeklyData(userList, null);
            });
        }
        executor.shutdown();
    }

    private void insertWeeklyData(List<EmoUserBean> userList, String weekOfYear) {

        int week = 0;
        int year = 0;
        String lastWeekOfYear;
        log.info("开始定时记录每个员工本周的平均快乐值======================");
        LocalDateTime localDateTime = LocalDateTime.now();
        long startMillis = System.currentTimeMillis();
        LocalDate now = LocalDate.now();
        log.info("now {}", localDateTime.format(DateTimeFormatHolder.FORMATTER_YYYY_MM_DD_HH_MM_SS));
        if (Objects.isNull(weekOfYear)) {
            //当前周数
            week = DateUtils.getWeek();
            //当前年数
            year = DateUtils.getYear();
            weekOfYear = String.format("%04d%02d", year, week);
        } else {
            //当前周数
            week = Integer.valueOf(String.valueOf(weekOfYear.charAt(4)) + String.valueOf(weekOfYear.charAt(5)));
            //当前年数
            year = Integer.parseInt(weekOfYear.substring(0, 4));
        }
        lastWeekOfYear = String.format("%04d%02d", year, week - 1);
        for (EmoUserBean emoUser : userList) {

            Long userId = emoUser.getUserId();
            computeUserDaily(now, emoUser, userId);

            //计算当前用户的本周 周均值
            BigDecimal weekAvg = dailyService.getCurrWeekHappinessScore(userId, weekOfYear);
            if (null == weekAvg || weekAvg.compareTo(BigDecimal.ZERO) == 0) {
                continue;
            }
            //先去查有没有当前周均值，如果有就更新，如果没有就新增
            EmoAvgScoreWeekly currWeekAvg = getWeekAvgScore(weekOfYear, userId);
            log.info("weekOfYear {}", weekOfYear);
            log.info("currWeekAvg {}", JsonUtils.toJsonString(currWeekAvg));
            log.info("userId {}", userId);
            //查询上周的周均值，计算较上周波动
            EmoAvgScoreWeekly lastWeekAvg = getWeekAvgScore(lastWeekOfYear, userId);
            log.info("lastWeekOfYear {}", lastWeekOfYear);
            log.info("lastWeekAvg {}", lastWeekAvg);
            log.info("userId {}", userId);

            if (StringUtils.isNull(currWeekAvg)) {
                currWeekAvg = new EmoAvgScoreWeekly()
                        .setUserId(userId)
                        .setWeek(Long.valueOf(week))
                        .setYear(Long.valueOf(year))
                        .setWeekOfYear(weekOfYear);
            }
            currWeekAvg.setScoreAvg(weekAvg);

            currWeekAvg.setScoreChanged(Objects.isNull(lastWeekAvg) ? BigDecimal.ZERO : weekAvg.subtract(lastWeekAvg.getScoreAvg()));

            if (StringUtils.isNotNull(emoUser)) {
                currWeekAvg.setNickName(emoUser.getNickName())
                        .setEmpno(emoUser.getEmpno());
            }
            log.info("saveOrUpdate currWeekAvg {}", currWeekAvg);
            weeklyService.saveOrUpdate(currWeekAvg);
        }
        long endMillis = System.currentTimeMillis();
        log.info("耗时 {}", endMillis - startMillis);
        log.info("结束定时记录每个员工本周的平均快乐值======================");
    }

    private void computeUserDaily(LocalDate now, EmoUserBean emoUser, Long userId) {
        //查出昨天日平均
        EmoAvgScoreDaily yesterdayDaily = dailyService.lambdaQuery()
                .eq(EmoAvgScoreDaily::getCurrDate, now.minusDays(1)).eq(EmoAvgScoreDaily::getUserId, userId).one();
        BigDecimal currHappinessScore = BigDecimal.valueOf(emoUser.getHappinessScore());
        log.info("yesterdayDaily {}", yesterdayDaily);
        log.info("userId {}", userId);

        //查询是否有今天的日均，如果有就更新，没有就新增
        EmoAvgScoreDaily daily = dailyService.lambdaQuery()
                .eq(EmoAvgScoreDaily::getCurrDate, now).eq(EmoAvgScoreDaily::getUserId, userId).one();
        log.info("daily {}", daily);
        log.info("userId {}", userId);

        if (StringUtils.isNull(daily)) {
            daily = new EmoAvgScoreDaily()
                    .setUserId(userId)
                    .setCurrDate(now)
                    .setScoreAvg(currHappinessScore);
        } else {
            daily.setScoreAvg(currHappinessScore);
        }

        if (StringUtils.isNotNull(emoUser)) {
            daily.setNickName(emoUser.getNickName())
                    .setEmpno(emoUser.getEmpno());
        }
        if (StringUtils.isNotNull(yesterdayDaily) && StringUtils.isNotNull(yesterdayDaily.getScoreAvg())) {
            daily.setScoreChanged(currHappinessScore.subtract(yesterdayDaily.getScoreAvg()));
        }
        log.info("saveOrUpdate daily {}", daily);
        dailyService.saveOrUpdate(daily);
    }


    private EmoAvgScoreWeekly getWeekAvgScore(String weekOfYear, Long userId) {
        return weeklyService.lambdaQuery()
                .eq(EmoAvgScoreWeekly::getWeekOfYear, weekOfYear)
                .eq(EmoAvgScoreWeekly::getUserId, userId).eq(EmoAvgScoreWeekly::getDeleted, Constants.UNDELETED).one();
    }


    /**
     * 根据weekofyear计算周均
     */
    public void computeWeekAvgScoreByWeekOfYear(String weekOfYear) {
        Long totalCount = 0L;
        R<Long> result = emoUserService.getCount(SecurityConstants.INNER);
        if (StringUtils.isNotNull(result) && StringUtils.isNotNull(result.getData())) {
            totalCount = result.getData();
        }
        final int runSize = 10;
        final int pageSize = 1000;
        final int pageCount = totalCount % pageSize == 0 ? totalCount.intValue() / pageSize : totalCount.intValue() / pageSize + 1;
        ThreadPoolExecutor executor = ThreadPoolConfig.createThread(runSize);
        // 计算sql语句中每个分页查询的起始和结束数据下标
        // 循环创建线程
        //此处调用具体的查询方法 0,100, 101 201 ,
        log.info("定时记录用户每周均值开始查询emo_user");
        for (int i = 0; i < pageCount; i++) {
            Integer page = i * pageSize;
            executor.execute(() -> {
                log.info("每次查询的下标:" + page + ",条数:" + pageSize);
                List<EmoUserBean> userList = new ArrayList<>();
                R<List<EmoUserBean>> resultList = emoUserService.selectByLimit(page, pageSize, SecurityConstants.INNER);
                if (StringUtils.isNotNull(resultList) && StringUtils.isNotNull(resultList.getData())) {
                    userList = resultList.getData();
                }
                insertWeeklyData(userList, weekOfYear);
            });
        }
        executor.shutdown();

        log.info("end {}", weekOfYear);
    }

}
